#include "types.h"
#include "biscuit.h"
#include "params.h"
#include "lock.h"
#include "kalloc.h"
#include "proc.h"
#include "kfunc.h"
#include "util.h"
#include "kobj.h"
#include "file.h"
// 等待调用LOCK

struct {
    struct file fs[NR_MFSFILE];
    int map[NR_MFSFILE];
    struct sleeplk lk;
    struct sleeplk devlk; // 设备锁
    struct file * devf; // 当前设备操作的文件
} mfs;


void
mfsinit () {
    bzero (&mfs, sizeof (mfs));
    int mfsctl;
    again:
    mfsctl = ll_r_mfsctl ();
    if ((mfsctl & MFSCTL_DEVREADY) == 0)
        goto again;
}

int
ls (char * udest) {
    struct filelist fls;
    struct proc * p;
    p = myproc ();
    int retval;
    bzero (&fls, sizeof (struct filelist));
    sleep_lock (&fls.lk);
    retval = fetch_filelist (&fls);
    vmwrite (p->pgtb, (char*)&fls, (unsigned int)udest, sizeof (struct filelist));
    return retval;
}

int
rm (char * name) {
    struct fpath pa;
    strncpy (pa.name, name, MAX_NAMESZ);
    int retval;
    bzero (&pa, sizeof (pa));
    sleep_lock(&pa.lk); // 在此加锁,
    retval = rm_file (&pa);
    return retval;
}

struct file *
allocfile (char * name) {
    int i;
    struct file * f;
    sleep_lock (&mfs.lk);
    for (i = 0; i < NR_MFSFILE; i++) {
        if (mfs.map[i] == 0) {
            mfs.map[i] = 1;
            f = &mfs.fs[i];
            bzero (f, sizeof (struct file));
            f->kbuf = kalloc ();
            sleep_lock (&f->lk); // 分配时执行lock,在调用时阻塞
            goto found;
        }
    }
    sleep_unlock (&mfs.lk);
    return 0;
    found:
    sleep_unlock (&mfs.lk);
    return f;
}

int
freefile (void * ctx) {
    struct file* f = (struct file*) ctx; 
    if (mfs.map[f->id] != 1)
        goto error;
    kfree (f->kbuf);
    mfs.map[f->id] = 0;
    error:
    return -1;
}

int
read_fileko (struct ko * o, void * to, unsigned int sz) {
    struct file * f = (struct file *) o->ctx;
    // sleep_lock (&f->lk); NOTE: 已在分配时加锁
    return readfile (f, to, sz);
}

int
readfile (struct file * f, void * to, unsigned int sz) {
    int rdsz;
    sleep_lock (&mfs.devlk);
    mfs.devf = f;
    //printk ("mfs invoking");
    ll_mfs_invoke ((int)f->name, (int)f->rptr,(int)f->kbuf,(int)sz, MFS_READ); // 中断将解除file的sleeplock
    ll_w_mfscratch ((int)f); // f指针
    sleep_lock (&f->lk); // 读写指针在traphandler上已更改
    // o->rptr = f->rptr;
    // o->wptr = o->wptr;
    rdsz = (int)ll_r_mfsret;
    sleep_unlock (&mfs.devlk);
    return rdsz;
}

int
writefile (struct file * f, void * from, unsigned int sz) {
    int wrsz;
    sleep_lock (&mfs.devlk);
    mfs.devf = f;
    ll_mfs_invoke ((int)f->name, (int)f->wptr, (int)f->kbuf,(int)sz, MFS_WRITE); // 中断将解除file的sleeplock
    ll_w_mfscratch ((int)f); // f指针
    sleep_lock (&f->lk); // 等待设备解除, 中断时应操作devf
    // o->rptr = f->rptr;  // 读写指针在traphandler上已更改
    // o->wptr = o->wptr;
    wrsz = (int)ll_r_mfsret;
    sleep_unlock (&mfs.devlk);
    return wrsz;
}

int
write_fileko (struct ko * o, void * from, unsigned int sz) {
    struct file * f = (struct file *) o->ctx;
    return writefile (f, from, sz);
}

int
fetch_filelist (struct filelist * fls) {
    int retval;
    sleep_lock (&mfs.devlk);
    ll_w_mfscratch ((int)fls);
    ll_mfs_invoke ((int)fls,0,0,0,MFS_FETCH);
    sleep_lock (&fls->lk);
    retval = ll_r_mfsret ();
    sleep_unlock (&mfs.devlk);
    return retval;
}

/* 约定:上层先调用sleep_lock */
int
rm_file (struct fpath * pa) {
    int retval;
    sleep_lock (&mfs.devlk);
    ll_w_mfscratch ((int)pa);
    ll_mfs_invoke ((int)pa, 0,0,0,MFS_RM);
    sleep_lock (&pa->lk); // 执行时会被阻塞
    retval = ll_r_mfsret ();
    sleep_unlock (&mfs.devlk);
    return retval;
}

void
mfs_intrhdlr () {
    int funct = ll_r_mfsfunct ();
    void * p = (void*)ll_r_mfscratch ();
    int retval = ll_r_mfsret ();
    struct file * f;
    struct fpath * fpa;
    struct filelist * fls;

    switch (funct) {
        case MFS_FETCH : {
            fls = (struct filelist*) p;
            SLEEPLK_BARRER (fls->lk);
            sleep_unlock (&fls->lk);
            break;
        }
        case MFS_RM : {
            fpa = (struct fpath*) p;
            SLEEPLK_BARRER (fpa->lk);
            sleep_unlock (&fpa->lk);
            break;
        }
        case MFS_READ : {
            f = (struct file*)p;
            if (retval != -1)
                f->rptr += retval; // 调整读指针
            SLEEPLK_BARRER(f->lk); 
            sleep_unlock (&f->lk);
            break;
        }
        case MFS_WRITE : {
            f = (struct file*)p;
            if (retval != -1)
                f->wptr += retval; // 调整写指针
            SLEEPLK_BARRER (f->lk);
            sleep_unlock(&f->lk);
            break;
        }
    }
}
